using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using Engine;
using Game;

namespace RuthlessConquest {
    public class ConnectingDialog : BusyDialog {
        public enum GameType {
            InProcess,
            Local,
            Internet
        }

        public Exception Error;
        public Server Server;
        public Client Client;
        public double FirstUpdateTime;
        public GameCreationParameters CreationParameters;
        public ServerDescription TargetServer;
        public const string fName = "RCConnectingDialog";

        public ConnectingDialog(GameDescription gameDescription, bool spectate) : base(
            LanguageControl.Get(fName, "1"),
            string.Format(LanguageControl.Get(fName, "2"), gameDescription.ServerDescription.Name)
        ) {
            try {
                Client = new Client(false);
                Client.JoinGame(gameDescription.ServerDescription.Address, gameDescription.GameId, spectate);
            }
            catch (Exception error) {
                Client?.Dispose();
                Error = error;
            }
        }

        public ConnectingDialog(GameCreationParameters creationParameters, GameType gameType, ServerDescription targetServer = null) : base(
            null,
            null
        ) {
            try {
                switch (gameType) {
                    case GameType.InProcess:
                        LargeMessage = LanguageControl.Get(fName, "3");
                        Server = new Server(false, true);
                        Client = new Client(true);
                        Client.CreateGame(Server.Peer.Address, creationParameters);
                        break;
                    case GameType.Local: {
                        LargeMessage = LanguageControl.Get(fName, "1");
                        SmallMessage = LanguageControl.Get(fName, "4");
                        Server = new Server(false, false);
                        Client = new Client(false);
                        IPEndPoint serverAddress = new(Client.Peer.Address.Address, Server.Peer.Address.Port);
                        Client.CreateGame(serverAddress, creationParameters);
                        break;
                    }
                    case GameType.Internet:
                        LargeMessage = LanguageControl.Get(fName, "5");
                        CreationParameters = creationParameters;
                        TargetServer = targetServer;
                        break;
                    default: throw new InvalidOperationException(LanguageControl.Get(fName, "6"));
                }
            }
            catch (Exception error) {
                Server?.Dispose();
                Client?.Dispose();
                Error = error;
            }
        }

        public override void Update() {
            base.Update();
            if (Error != null) {
                DialogsManager.HideDialog(this);
                if (Error is SocketException ex) {
                    DialogsManager.ShowDialog(
                        null,
                        new MessageDialog(
                            LanguageControl.Get(fName, "7"),
                            string.Format(LanguageControl.Get(fName, "8"), ex.SocketErrorCode, (int)ex.SocketErrorCode),
                            LanguageControl.Ok,
                            null,
                            null
                        )
                    );
                }
                else {
                    DialogsManager.ShowDialog(null, new MessageDialog(LanguageControl.Error, Error.Message, LanguageControl.Ok, null, null));
                }
                return;
            }
            if (FirstUpdateTime == 0.0) {
                FirstUpdateTime = Time.FrameStartTime;
            }
            if (Client != null) {
                if (Client.Game != null) {
                    if (Time.FrameStartTime - FirstUpdateTime > 0.75) {
                        DialogsManager.HideDialog(this);
                        ScreensManager.SwitchScreen("RCGame", Server, Client);
                    }
                }
                else if (Client.Error != null) {
                    DialogsManager.HideDialog(this);
                    bool notFound = true;
                    foreach (Dialog dialog in DialogsManager.Dialogs) {
                        if (dialog is MessageDialog messageDialog) {
                            notFound = false;
                            messageDialog.LargeLabelWidget.Text = LanguageControl.Get(fName, "9");
                            messageDialog.SmallLabelWidget.Text = Client.Error.Message;
                            messageDialog.Button1Widget.Text = LanguageControl.Ok;
                            messageDialog.Button1Widget.IsVisible = true;
                            messageDialog.Button2Widget.IsVisible = false;
                            messageDialog.Handler = null;
                        }
                    }
                    if (notFound) {
                        DialogsManager.ShowDialog(
                            null,
                            new MessageDialog(LanguageControl.Get(fName, "9"), Client.Error.Message, LanguageControl.Ok, null, null)
                        );
                    }
                    Client.Dispose();
                    Server?.Dispose();
                }
            }
            else if (TargetServer == null) {
                if (ServersManager.DiscoveredServers.Count > 0) {
                    if (Time.FrameStartTime > FirstUpdateTime + 1.0) {
                        ServerDescription serverDescription = ServersManager.DiscoveredServers.OrderByDescending(s => 1000000.0 * s.Priority - s.Ping)
                            .First();
                        Client = new Client(false);
                        Client.CreateGame(serverDescription.Address, CreationParameters);
                        SmallMessage = string.Format(LanguageControl.Get(fName, "2"), serverDescription.Name);
                    }
                }
                else {
                    ServersManager.StartServerDiscovery(1.0);
                    if (Time.FrameStartTime > FirstUpdateTime + 6.0) {
                        DialogsManager.HideDialog(this);
                        if (!DialogsManager.Dialogs.Any(d => d is MessageDialog md && md.LargeLabelWidget.Text == LanguageControl.Get(fName, "10"))) {
                            DialogsManager.ShowDialog(
                                null,
                                new MessageDialog(LanguageControl.Get(fName, "10"), LanguageControl.Get(fName, "11"), LanguageControl.Ok, null, null)
                            );
                        }
                    }
                }
            }
            else if (Time.FrameStartTime > FirstUpdateTime + 1.0) {
                Client = new Client(false);
                Client.CreateGame(TargetServer.Address, CreationParameters);
                SmallMessage = string.Format(LanguageControl.Get(fName, "2"), TargetServer.Name);
            }
            if (Input.Back
                || (Input.Tap.HasValue && !HitTest(Input.Tap.Value))) {
                DialogHidden();
                DialogsManager.HideDialog(this);
            }
        }

        public void DialogHidden() {
            if (ServersManager.IsDiscoveryStarted) {
                ServersManager.StartServerDiscovery();
            }
        }
    }
}